home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
AMICUS
/
AMICUS04.ADF
/
text
/
autorequester.txt
next >
Wrap
Text File
|
1985-11-16
|
16KB
|
399 lines
TITLE: Deadlock with AutoRequest()
WARNING! We have had several people fall prey to a rather subtle
deadlock situation involving AutoRequest() and (usually) the
MENUVERIFY mode of Intuition. Other Intuition xVERIFY modes have
similar potential for deadlock as well.
AutoRequest() is the Intuition function used to build simple
Requesters -- usually used for error processing. It blocks the
requesting task until the user responds by selecting an exit
gadget of the requester. AutoRequest() is built on top of
BuildSysRequest() which, currently, makes a new window and
installs your requester in it.
MENUVERIFY is the Intuition menu handling mode which causes Intuition
to send a message to your task if your window is the Active window
and the user presses the Menu button (the right-hand button) on the
mouse. Intuition will hold off doing all normal interactive
processing until you reply to that message. Your reply indicates
either that you've done any clean-up processing and Intuition can
go display the menu, or that you want Intuition to ignore this
menu request and let you handle the Right Mouse Button (RMB) yourself
this time. Your delay before replying should be short because the
system appears hung to the user until you reply to Intuition.
You must NOT call AutoRequest() while MENUVERIFY is in effect in any
window controlled by your task. If you do so, and if your window becomes
the Active window, then if the user presses the Menu button you will be in
a deadlock. Your task can't procede because the user hasn't selected
an exit gadget on the Requester. The user can't select that gadget
because Intuition is stuck in MENUVERIFY waiting for your task to reply.
Your task can't reply because it's blocked behind the Requester.
The subtlety is that AmigaDOS may generate an AutoRequest() FOR YOU
if an I/O error happens during an AmigaDOS call.
If an I/O error occurs during an AmigaDOS I/O call, AmigaDOS looks
at the pr_WindowPtr field of the Process structure for the process
that generated the call. [An AmigaDOS Process is an EXEC Task plus
a little extra context. See the dosextens.h or dosextens.i include
files for info.] If that field is -1, then AmigaDOS returns the
error to the requesting process in the normal fashion. If that
field is >=0, then AmigaDOS puts up a system requester using the
AutoRequest() facility. If pr_WindowPtr is 0, that requester is
put up in a new window in the Workbench screen. If pr_WindowPtr
is positive, then it is interpreted as a pointer to a Window
structure -- usually the control window for your program. In the
current implementation, AmigaDOS puts up the requester in a new
window in the same screen as the specified window. Certain unlikely
I/O errors are detected so deeply in the file system that their
requesters can ONLY appear in the Workbench screen even if you
have specified a window.
The pr_WindowPtr field is inherited from your process creator. Normally
it's 0 when your process starts. If you change the field, you must be
sure to change it back before your program exits. This is because
you may be running as a co-routine of a CLI in the CLI process context.
If you leave the pointer set to a window that you've just closed, the
CLI will probably crash the system the next time it gets an I/O error.
Not all I/O errors will generate requesters. The ones that do are
the ones that the user can be expected to correct. These include
Write Protected disks and Wrong Disk in drive. For more information
on this processing, see the AmigaDOS Technical Reference Manual
chapter on DOS Data Structures.
The upshot of all this is that you shouldn't do AmigaDOS I/O calls
while you have MENUVERIFY set and a pr_WindowPtr of other than -1.
If you do, there is a chance that AmigaDOS will be forced to put
up a system requester. In that case, if the user is so unfortunate
as to hit the Menu button, while your window is the Active window,
you will be in deadlock.
Note that if you intend to do ALL your own Right Mouse Button
processing, you can set the RMBTRAP flag in your Window structure
without concern about deadlocks. The value of the MENUVERIFY stuff
is limited to those cases where you WANT Intuition to do Menu
processing, but you don't want it to do so just now. For more
information on all of this refer to the manual Intuition: The
Amiga User Interface.
PRELIMINARY INFORMATION... CURRENTLY UNDER REVIEW.
DOESN'T DESCRIBE THE set mouse port FUNCTIONS.
MAY CONTAIN MINOR INACCURACIES IN THE SAMPLE PROGRAM SEGMENT.
(printed version available approx 11/18/85, reviewed and correct-
ed).
Rob Peck.
Chapter 1
Input Device
This chapter describes the Amiga input device, which is a combi-
nation of three other devices: keyboard device, gameport device,
and timer device. The input device merges separate input event
streams from the keyboard, mouse, and timer into a single stream.
This single stream can then be interpreted by the prioritized
linked list of input handlers that are watching the input stream.
1.1. OVERVIEW
The input device is automatically opened by AmigaDOS by any call
to open the console device. When the input device is opened, a
task, appropriately named ``input.device'', is started. The
input device task communicates directly with the keyboard device
to obtain raw key inputs. It also communicates with the gameport
device to obtain mouse button and mouse movement events and with
the timer device to obtain time events. In addition to these
event streams, you can also directly input an event to the input
device, to be fed to the handler chain. This topic is also
covered below.
The keyboard device is also accessible directly. However, while
the input device task is operating, it attempts to retrieve all
incoming keyboard events and add them to the input stream.
The gameport device has two units available to it. As you view
the Amiga looking at the gameport connectors, connector ``1'' is
assigned as the primary mouse input for Intuition and contributes
gameport input events to the input event stream. Connector ``2''
is handled by the other gameport unit and is currently unas-
signed. Each unit of the gameport device is an exclusive access
object, in that you can specify what type of controller is
attached. It is then assumed that only one task is sending
requests for input from that unit. While the input device task
is running, that task expects to read the input from connector 1.
Direct use of the gameport device is covered in a separate
chapter of this manual.
November 13, 1985
- 2 -
The timer device provides time events for the input device. It
also provides time interval reports for controlling key repeat
rate and key repeat threshold. The timer device is a shared-
access device and is described in its own separate section.
1.2. INPUT DEVICE COMMANDS
The input device allows the following system functions:
box; ci ci l l.
COMMAND OPERATION
=
OpenDevice() Obtain shared use of the input device.
CloseDevice() Relinquish use of the input device.
DoIO() Initiate a command, and wait for it to complete.
SendIO() Initiate a command, and return immediately.
AbortIO() Abort a command already in the queue.
Only the Start, Stop, Invalid, and Flush commands have been
implemented for this device. All other commands are no-
operations.
The input device also supports the following device-specific com-
mands:
Table 1-1: Input Device Commands
box; ci ci l l.
I/O COMMAND OPERATION
=
IND_WRITEEVENT Propagate an input event stream to all dev-
ices IND_ADDHANDLER Add an input-stream handler into the
handler chain. IND_REMHANDLER Remove an input-stream
handler from the handler chain. IND_SETTHRESH Set
the repeating key hold-down time before repeat
starts. IND_SETPERIOD Set the period at which a
repeating key repeats. IND_SETMPORT Set the gameport port
to which the mouse is connected.
IND_SETTRIGGER Read conditions that must be met by a mouse
before a pending read request will be satisfied.
IND_SETMTYPE Set the type of device at the mouse port.
The device-specific commands outlined above are described in the
following paragraphs. A description of the contents of an input
event is given first because the input device deals in input
November 13, 1985
- 3 -
events. An input event is a data structure that describes:
o the class of the event-often describes the device that
generated the event
o the subclass of the event-space for more information if
needed
o the code-keycode if keyboard, button information if
mouse, others
o a qualifier such as ``ALT key also down'', ``key repeat
active''
o a position field which contains a data address or a mouse
position count.
o a time stamp, showing the sequence in which events have
occurred
o a link-field by which input events are linked together
The various types of input events are listed in the include-file
devices/inputevent.h. That information is not repeated here.
You can find more information about input events in the chapters
titled ``Gameport Device'' and ``Console Device''.
There is a difference between simply receiving an input event
from a device (gameport, keyboard, or console) and actually
becoming a handler of an input event stream. A handler is a rou-
tine that is passed an input event, and it is up to the handler
to decide if it can process the input event. If the handler does
not recognize the event, it passes the address of the event as a
return value.
Because of the input event field called ie_NextEvent, it is pos-
sible for the input event to be a pointer to the first event in a
linked list of events to be handled. Thus the handler should be
designed to handle multiple events if such a link is used. Note
that handlers can, themselves, generate new linked lists of
events which can be passed down to lower priority handlers.
You add a handler to the chain by the command IND_ADDHANDLER.
Assuming that you have a properly initialized an IOStdReq block
as a result of a call to OpenDevice() (for the input device),
here is a typical C-language call to the IND_ADDHANDLER function:
November 13, 1985
- 4 -
struct Interrupt handlerStuff;
handlerStuff.is_Data = &hsData;
/* address of its data area */
handlerStuff.is_Code = myhandler;
/* address of entry point to handler */
handlerStuff.is_Node.ln_Pri = 51;
/* set the priority one step higher than
* Intution, so that our handler enters
* the chain ahead of Intuition.
*/
inputRequestBlock.io_Command = IND_ADDHANDLER;
inputRequestBlock.io_Data = &handlerStuff;
DoIO(&inputRequestBlock);
Notice from the above that Intuition is one of the input device
handlers and normally distributes all of the input events.
Intuition inserts itself at priority position 50. You can choose
the position in the chain at which your handler will be inserted
by setting the priority field in the list-node part of the inter-
rupt data structure you are feeding to this routine.
Note also that any processing time expended by a handler sub-
tracts from the time available before the next event happens.
Therefore, handlers for the input stream must be fast.
Rules for Input Device Handlers
The following rules should be followed when you are designing an
input handler:
1. If an input handler is capable of processing a specific
kind of an input event and that event has no links
(ie_NextEvent = 0), the handler can end the handler chain
by returning a NULL (0) value.
2. If there are multiple events linked together, the handler
can feel free to delink an event from the input event
chain, thereby passing a shorter list of events to subse-
quent handlers. The starting address of the modified
list is the return value.
3. If a handler wishes to add new events to the chain that
it passes to a lower priority handler, it may initialize
memory to contain the new event or event chain. The
handler, when it again gets control on the next round of
event handling, should assume nothing about the current
contents of the memory blocks it attached to the event
chain. Lower priority handlers may have modified the
November 13, 1985
- 5 -
memory as they handled their part of the event. The
handler that allocates the memory for this purpose should
keep track of the starting address and the size of this
memory chunk so that the memory can be returned to the
free memory list when it is no longer needed.
Your routine should be structured so that it can be called as
though from the following assembler language statement:
newEventChain = yourHandlerCode(oldEventChain, yourHandlerData);
where:
o yourHandlerCode is the entry point to your routine,
o oldEventChain is the starting address for the current
chain of input events, and
o newEventChain is the starting address of an event chain
which you are passing to the next handler, if any.
A NULL (0) value terminates the handling.
Memory that you use to describe a new input event that you've
added to the event chain is available for re-use or deallocation
when the handler is called again or after the IND_REMHANDLER com-
mand for the handler is complete.
Because IND_ADDHANDLER installs a handler in any position in the
handler chain, it can, for example, ignore specific types of
input events as well as act upon and modify existing streams of
input. It can even create new input events for Intuition or
other programs to interpret.
You remove a handler from the handler chain with the command
IND_REMHANDLER. Assuming that you have a properly initialized
IOStdReq block as a result of a call to OpenDevice() (for the
input device) and you have already added the handler using
IND_ADDHANDLER, here is a typical C-language call to the
IND_REMHANDLER function:
inputRequestBlock.io_Command = IND_REMHANDLER;
inputRequestBlock.io_Da